home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 16 / Example 16.1 / terrain.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-17  |  35.8 KB  |  1,293 lines

  1. #include "terrain.h"
  2. #include "camera.h"
  3. #include "mapObject.h"
  4.  
  5. const DWORD TERRAINVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX2;
  6.  
  7. //////////////////////////////////////////////////////////////////////////////////////////
  8. //                                    PATCH                                                //
  9. //////////////////////////////////////////////////////////////////////////////////////////
  10.  
  11. PATCH::PATCH()
  12. {
  13.     m_pDevice = NULL;
  14.     m_pMesh = NULL;
  15. }
  16. PATCH::~PATCH()
  17. {
  18.     Release();
  19. }
  20.  
  21. void PATCH::Release()
  22. {
  23.     if(m_pMesh != NULL)
  24.         m_pMesh->Release();
  25.     m_pMesh = NULL;
  26. }
  27.  
  28. HRESULT PATCH::CreateMesh(TERRAIN &ter, RECT source, IDirect3DDevice9* Dev)
  29. {
  30.     if(m_pMesh != NULL)
  31.     {
  32.         m_pMesh->Release();
  33.         m_pMesh = NULL;
  34.     }
  35.  
  36.     try
  37.     {
  38.         m_pDevice = Dev;
  39.         m_mapRect = source;
  40.  
  41.         int width = source.right - source.left;
  42.         int height = source.bottom - source.top;
  43.         int nrVert = (width + 1) * (height + 1);
  44.         int nrTri = width * height * 2;
  45.  
  46.         if(FAILED(D3DXCreateMeshFVF(nrTri, nrVert, D3DXMESH_MANAGED, TERRAINVertex::FVF, m_pDevice, &m_pMesh)))
  47.         {
  48.             debug.Print("Couldn't create mesh for PATCH");
  49.             return E_FAIL;
  50.         }
  51.  
  52.         m_BBox.max = D3DXVECTOR3(-10000.0f, -10000.0f, -10000.0f);
  53.         m_BBox.min = D3DXVECTOR3(10000.0f, 10000.0f, 10000.0f);
  54.  
  55.         //Create vertices
  56.         TERRAINVertex* ver = 0;
  57.         m_pMesh->LockVertexBuffer(0,(void**)&ver);
  58.         for(int z=source.top, z0 = 0;z<=source.bottom;z++, z0++)
  59.             for(int x=source.left, x0 = 0;x<=source.right;x++, x0++)
  60.             {
  61.                 MAPTILE *tile = ter.GetTile(x, z);
  62.  
  63.                 D3DXVECTOR3 pos = D3DXVECTOR3(x, tile->m_height, -z);
  64.                 D3DXVECTOR2 alphaUV = D3DXVECTOR2(x / (float)ter.m_size.x, z / (float)ter.m_size.y);        //Alpha UV
  65.                 D3DXVECTOR2 colorUV = alphaUV * 8.0f;                                                    //Color UV
  66.  
  67.                 ver[z0 * (width + 1) + x0] = TERRAINVertex(pos, ter.GetNormal(x, z), alphaUV, colorUV);
  68.  
  69.                 //Calculate bounding box bounds...
  70.                 if(pos.x < m_BBox.min.x)m_BBox.min.x = pos.x;
  71.                 if(pos.x > m_BBox.max.x)m_BBox.max.x = pos.x;
  72.                 if(pos.y < m_BBox.min.y)m_BBox.min.y = pos.y;
  73.                 if(pos.y > m_BBox.max.y)m_BBox.max.y = pos.y;
  74.                 if(pos.z < m_BBox.min.z)m_BBox.min.z = pos.z;
  75.                 if(pos.z > m_BBox.max.z)m_BBox.max.z = pos.z;
  76.             }
  77.         m_pMesh->UnlockVertexBuffer();
  78.  
  79.         //Calculate Indices
  80.         WORD* ind = 0;
  81.         m_pMesh->LockIndexBuffer(0,(void**)&ind);    
  82.         int index = 0;
  83.  
  84.         for(int z=source.top, z0 = 0;z<source.bottom;z++, z0++)
  85.             for(int x=source.left, x0 = 0;x<source.right;x++, x0++)
  86.             {
  87.                 //Triangle 1
  88.                 ind[index++] =   z0   * (width + 1) + x0;
  89.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  90.                 ind[index++] = (z0+1) * (width + 1) + x0;        
  91.  
  92.                 //Triangle 2
  93.                 ind[index++] = (z0+1) * (width + 1) + x0;
  94.                 ind[index++] =   z0   * (width + 1) + x0 + 1;
  95.                 ind[index++] = (z0+1) * (width + 1) + x0 + 1;
  96.             }
  97.  
  98.         m_pMesh->UnlockIndexBuffer();
  99.  
  100.         //Set Attributes
  101.         DWORD *att = 0, a = 0;
  102.         m_pMesh->LockAttributeBuffer(0,&att);
  103.         memset(att, 0, sizeof(DWORD)*nrTri);
  104.         m_pMesh->UnlockAttributeBuffer();
  105.     }
  106.     catch(...)
  107.     {
  108.         debug.Print("Error in PATCH::CreateMesh()");
  109.         return E_FAIL;
  110.     }
  111.  
  112.     return S_OK;
  113. }
  114.  
  115. void PATCH::Render()
  116. {
  117.     //Draw mesh
  118.     if(m_pMesh != NULL)
  119.         m_pMesh->DrawSubset(0);
  120. }
  121.  
  122. //////////////////////////////////////////////////////////////////////////////////////////
  123. //                                    TERRAIN                                                //
  124. //////////////////////////////////////////////////////////////////////////////////////////
  125.  
  126. TERRAIN::TERRAIN()
  127. {
  128.     m_pDevice = NULL;
  129.     m_pMapTiles = NULL;
  130.     m_pVisitedTiles = m_pVisibleTiles = NULL;
  131.     m_pLandScape = m_pLightMap = m_pFogOfWarTexture = NULL;
  132. }
  133.  
  134. void TERRAIN::Init(IDirect3DDevice9* Dev, INTPOINT _size)
  135. {
  136.     m_pDevice = Dev;
  137.     m_size = _size;
  138.     m_pHeightMap = NULL;
  139.     m_updateSight = true;
  140.  
  141.     if(m_pMapTiles != NULL)    //Clear old maptiles
  142.         delete [] m_pMapTiles;
  143.  
  144.     //Create maptiles
  145.     m_pMapTiles = new MAPTILE[m_size.x * m_size.y];
  146.     memset(m_pMapTiles, 0, sizeof(MAPTILE)*m_size.x*m_size.y);
  147.  
  148.     //Clear old textures
  149.     for(int i=0;i<m_diffuseMaps.size();i++)
  150.         m_diffuseMaps[i]->Release();
  151.     m_diffuseMaps.clear();
  152.  
  153.     //Load textures
  154.     IDirect3DTexture9* grass = NULL, *mount = NULL, *snow = NULL;
  155.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/grass.jpg", &grass)))    debug.Print("Could not load grass.jpg");
  156.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/mountain.jpg", &mount)))    debug.Print("Could not load stone.dds");
  157.     if(FAILED(D3DXCreateTextureFromFile(Dev, "textures/snow.jpg", &snow)))        debug.Print("Could not load snow.dds");
  158.     m_diffuseMaps.push_back(grass);
  159.     m_diffuseMaps.push_back(mount);
  160.     m_diffuseMaps.push_back(snow);
  161.     m_pAlphaMap = NULL;
  162.     m_pLightMap = NULL;
  163.  
  164.     //Fog-of-War texture
  165.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pFogOfWarTexture, NULL)))debug.Print("Failed to create texture: m_pFogOfWarTexture");
  166.  
  167.     //Terrain Texture
  168.     if(FAILED(m_pDevice->CreateTexture(256, 256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pLandScape, NULL)))debug.Print("Failed to create texture: m_pLandScape");
  169.  
  170.     // Init font
  171.     D3DXCreateFont(m_pDevice, 40, 0, 0, 1, false,  
  172.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  173.                    DEFAULT_PITCH | FF_DONTCARE, "Arial Black", &m_pProgressFont);
  174.  
  175.     Progress("Creating Terrain", 0.0f);
  176.  
  177.     //Load pixel & vertex shaders
  178.     m_dirToSun = D3DXVECTOR3(1.0f, 0.6f, 0.5f);
  179.     D3DXVec3Normalize(&m_dirToSun, &m_dirToSun);
  180.  
  181.     m_terrainPS.Init(Dev, "shaders/terrain.ps", PIXEL_SHADER);
  182.     m_terrainVS.Init(Dev, "shaders/terrain.vs", VERTEX_SHADER);
  183.     m_vsMatW = m_terrainVS.GetConstant("matW");
  184.     m_vsMatVP = m_terrainVS.GetConstant("matVP");
  185.     m_vsDirToSun = m_terrainVS.GetConstant("DirToSun");
  186.  
  187.     m_objectsPS.Init(Dev, "shaders/objects.ps", PIXEL_SHADER);
  188.     m_objectsVS.Init(Dev, "shaders/objects.vs", VERTEX_SHADER);
  189.     m_objMatW = m_objectsVS.GetConstant("matW");
  190.     m_objMatVP = m_objectsVS.GetConstant("matVP");
  191.     m_objDirToSun = m_objectsVS.GetConstant("DirToSun");
  192.     m_objMapSize = m_objectsVS.GetConstant("mapSize");
  193.  
  194.     //Create white material    
  195.     m_mtrl.Ambient = m_mtrl.Specular = m_mtrl.Diffuse  = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
  196.     m_mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  197.  
  198.     //Create visited & m_visible tiles
  199.     if(m_pVisitedTiles)delete [] m_pVisitedTiles;
  200.     if(m_pVisibleTiles)delete [] m_pVisibleTiles;
  201.     m_pVisitedTiles = new bool[m_size.x * m_size.y];
  202.     m_pVisibleTiles = new bool[m_size.x * m_size.y];
  203.     memset(m_pVisitedTiles, false, sizeof(bool)* m_size.x * m_size.y);
  204.     memset(m_pVisibleTiles, false, sizeof(bool)* m_size.x * m_size.y);
  205.  
  206.     Progress("Creating Terrain", 0.4f);
  207.  
  208.     GenerateRandomTerrain(15);
  209. }
  210.  
  211. void TERRAIN::Release()
  212. {
  213.     try
  214.     {
  215.         for(int i=0;i<m_patches.size();i++)
  216.             if(m_patches[i] != NULL)
  217.                 m_patches[i]->Release();
  218.  
  219.         m_patches.clear();
  220.  
  221.         if(m_pHeightMap != NULL)
  222.         {
  223.             m_pHeightMap->Release();
  224.             delete m_pHeightMap;
  225.             m_pHeightMap = NULL;
  226.         }
  227.  
  228.         m_objects.clear();
  229.     }
  230.     catch(...)
  231.     {
  232.         debug.Print("Error in TERRAIN::Release()");
  233.     }
  234. }
  235.  
  236. void TERRAIN::GenerateRandomTerrain(int numPatches)
  237. {
  238.     try
  239.     {
  240.         Release();
  241.  
  242.         //Create two heightmaps and multiply them
  243.         m_pHeightMap = new HEIGHTMAP(m_size, 20.0f);
  244.         HEIGHTMAP hm2(m_size, 2.0f);
  245.         HEIGHTMAP hm3(m_size, 2.0f);
  246.  
  247.         m_pHeightMap->CreateRandomHeightMap(rand()%2000, 1.0f, 0.7f, 7);
  248.         hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.8f, 3);
  249.  
  250.         //Load 4 player filter
  251.         hm3.LoadFromFile(m_pDevice, "heightmaps/four_players.jpg");
  252.         hm2.Cap(hm2.m_maxHeight * 0.4f);
  253.  
  254.         *m_pHeightMap *= hm2;
  255.         *m_pHeightMap *= hm3;
  256.         hm2.Release();        
  257.         hm3.Release();
  258.  
  259.         //Add objects
  260.         HEIGHTMAP hm4(m_size, 1.0f);
  261.         hm4.CreateRandomHeightMap(rand()%1000, 5.5f, 0.9f, 7);
  262.  
  263.         for(int y=0;y<m_size.y;y++)
  264.             for(int x=0;x<m_size.x;x++)
  265.             {
  266.                 if(m_pHeightMap->GetHeight(x, y) == 0.0f && hm4.GetHeight(x, y) > 0.7f && rand()%12 == 0)
  267.                     AddObject(0, INTPOINT(x, y));    //Tree
  268.                 else if(m_pHeightMap->GetHeight(x, y) >= 1.0f && hm4.GetHeight(x, y) > 0.9f && rand()%30 == 0)
  269.                     AddObject(1, INTPOINT(x, y));    //Stone
  270.             }
  271.  
  272.         hm4.Release();        
  273.  
  274.         InitPathfinding();
  275.         CreatePatches(numPatches);
  276.  
  277.         CalculateAlphaMaps();
  278.         CalculateLightMap(false);
  279.  
  280.         RenderLandscape();
  281.     }
  282.     catch(...)
  283.     {
  284.         debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
  285.     }
  286. }
  287.  
  288. void TERRAIN::CreatePatches(int numPatches)
  289. {
  290.     try
  291.     {
  292.         //Clear any old patches
  293.         for(int i=0;i<m_patches.size();i++)
  294.             if(m_patches[i] != NULL)
  295.                 m_patches[i]->Release();
  296.         m_patches.clear();
  297.  
  298.         //Create new patches
  299.         for(int y=0;y<numPatches;y++)
  300.         {
  301.             Progress("Creating Terrain Mesh", y / (float)numPatches);
  302.  
  303.             for(int x=0;x<numPatches;x++)
  304.             {
  305.                 RECT r = {x * (m_size.x - 1) / (float)numPatches, 
  306.                         y * (m_size.y - 1) / (float)numPatches, 
  307.                         (x+1) * (m_size.x - 1) / (float)numPatches,
  308.                         (y+1) * (m_size.y - 1) / (float)numPatches};
  309.                         
  310.                 PATCH *p = new PATCH();
  311.                 p->CreateMesh(*this, r, m_pDevice);
  312.                 m_patches.push_back(p);
  313.             }
  314.         }
  315.     }
  316.     catch(...)
  317.     {
  318.         debug.Print("Error in TERRAIN::CreatePatches()");
  319.     }
  320. }
  321.  
  322. void TERRAIN::CalculateAlphaMaps()
  323. {
  324.     Progress("Creating Alpha Map", 0.0f);
  325.  
  326.     //Clear old alpha maps
  327.     if(m_pAlphaMap != NULL)
  328.         m_pAlphaMap->Release();
  329.  
  330.     //Create new alpha map
  331.     D3DXCreateTexture(m_pDevice, 128, 128, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pAlphaMap);
  332.  
  333.     //Lock the texture
  334.     D3DLOCKED_RECT sRect;
  335.     m_pAlphaMap->LockRect(0, &sRect, NULL, NULL);
  336.     BYTE *bytes = (BYTE*)sRect.pBits;
  337.     memset(bytes, 0, 128*sRect.Pitch);        //Clear texture to black
  338.  
  339.     for(int i=0;i<m_diffuseMaps.size();i++)
  340.         for(int y=0;y<sRect.Pitch / 4;y++)
  341.             for(int x=0;x<sRect.Pitch / 4;x++)
  342.             {
  343.                 int terrain_x = m_size.x * (x / (float)(sRect.Pitch / 4.0f));
  344.                 int terrain_y = m_size.y * (y / (float)(sRect.Pitch / 4.0f));
  345.                 MAPTILE *tile = GetTile(terrain_x, terrain_y);
  346.  
  347.                 if(tile != NULL && tile->m_type == i)
  348.                     bytes[y * sRect.Pitch + x * 4 + i] = 255;
  349.             }
  350.  
  351.     //Unlock the texture
  352.     m_pAlphaMap->UnlockRect(0);
  353.     
  354.     //D3DXSaveTextureToFile("alpha.bmp", D3DXIFF_BMP, m_pAlphaMap, NULL);
  355. }
  356.  
  357. void TERRAIN::CalculateLightMap(bool allWhite)
  358. {
  359.     try
  360.     {
  361.         //Clear old alpha maps
  362.         if(m_pLightMap != NULL)
  363.             m_pLightMap->Release();
  364.  
  365.         //Create new light map
  366.         D3DXCreateTexture(m_pDevice, 128, 128, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &m_pLightMap);
  367.  
  368.         //Lock the texture
  369.         D3DLOCKED_RECT sRect;
  370.         m_pLightMap->LockRect(0, &sRect, NULL, NULL);
  371.         BYTE *bytes = (BYTE*)sRect.pBits;
  372.         memset(bytes, 255, sRect.Pitch*sRect.Pitch);        //Clear texture to white
  373.  
  374.         if(allWhite)
  375.         {
  376.             m_pLightMap->UnlockRect(0);
  377.             return;
  378.         }
  379.  
  380.         for(int y=0;y<sRect.Pitch;y++)
  381.         {
  382.             Progress("Calculating Lightmap", y / (float)sRect.Pitch);
  383.  
  384.             for(int x=0;x<sRect.Pitch;x++)
  385.             {
  386.                 float terrain_x = (float)m_size.x * (x / (float)(sRect.Pitch));
  387.                 float terrain_z = (float)m_size.y * (y / (float)(sRect.Pitch));
  388.  
  389.                 //Find patch that the terrain_x, terrain_z is over
  390.                 bool done = false;
  391.                 for(int p=0;p<m_patches.size() && !done;p++)
  392.                 {
  393.                     RECT mr = m_patches[p]->m_mapRect;
  394.  
  395.                     //Focus within patch maprect or not?
  396.                     if(terrain_x >= mr.left && terrain_x < mr.right &&
  397.                          terrain_z >= mr.top && terrain_z < mr.bottom)
  398.                     {            
  399.                         // Collect only the closest intersection
  400.                         RAY rayTop(D3DXVECTOR3(terrain_x, 10000.0f, -terrain_z), D3DXVECTOR3(0.0f, -1.0f, 0.0f));
  401.                         float dist = rayTop.Intersect(m_patches[p]->m_pMesh);
  402.  
  403.                         if(dist >= 0.0f)
  404.                         {
  405.                             RAY ray(D3DXVECTOR3(terrain_x, 10000.0f - dist + 0.01f, -terrain_z), m_dirToSun);
  406.  
  407.                             for(int p2=0;p2<m_patches.size() && !done;p2++)
  408.                                 if(ray.Intersect(m_patches[p2]->m_BBox) >= 0)
  409.                                 {
  410.                                     if(ray.Intersect(m_patches[p2]->m_pMesh) >= 0)    //In shadow
  411.                                     {
  412.                                         done = true;
  413.                                         bytes[y * sRect.Pitch + x] = 128;
  414.                                     }
  415.                                 }
  416.  
  417.                             done = true;
  418.                         }
  419.                     }
  420.                 }                        
  421.             }
  422.         }
  423.  
  424.         //Smooth lightmap        
  425.         for(int i=0;i<3;i++)
  426.         {
  427.             Progress("Smoothing the Lightmap", i / 3.0f);
  428.  
  429.             BYTE* tmpBytes = new BYTE[sRect.Pitch * sRect.Pitch];
  430.             memcpy(tmpBytes, sRect.pBits, sRect.Pitch * sRect.Pitch);
  431.  
  432.             for(int y=1;y<sRect.Pitch-1;y++)
  433.                 for(int x=1;x<sRect.Pitch-1;x++)
  434.                 {
  435.                     long index = y*sRect.Pitch + x;
  436.                     BYTE b1 = bytes[index];
  437.                     BYTE b2 = bytes[index - 1];
  438.                     BYTE b3 = bytes[index - sRect.Pitch];
  439.                     BYTE b4 = bytes[index + 1];
  440.                     BYTE b5 = bytes[index + sRect.Pitch];
  441.                     
  442.                     tmpBytes[index] = (BYTE)((b1 + b2 + b3 + b4 + b5) / 5);
  443.                 }
  444.  
  445.             memcpy(sRect.pBits, tmpBytes, sRect.Pitch * sRect.Pitch);
  446.             delete [] tmpBytes;
  447.         }
  448.  
  449.         //Unlock the texture
  450.         m_pLightMap->UnlockRect(0);
  451.         
  452.         //D3DXSaveTextureToFile("light.bmp", D3DXIFF_BMP, m_pLightMap, NULL);
  453.     }
  454.     catch(...)
  455.     {
  456.         debug.Print("Error in TERRAIN::CalculateLightMap()");
  457.     }
  458. }
  459.  
  460. D3DXVECTOR3 TERRAIN::GetNormal(int x, int y)
  461. {
  462.     //Neighboring map nodes (D, B, C, F, H, G)
  463.     INTPOINT mp[] = {INTPOINT(x-1, y),   INTPOINT(x, y-1), 
  464.                      INTPOINT(x+1, y-1), INTPOINT(x+1, y),
  465.                        INTPOINT(x, y+1),   INTPOINT(x-1, y+1)};
  466.  
  467.     //if there's an invalid map node return (0, 1, 0)
  468.     if(!Within(mp[0]) || !Within(mp[1]) || !Within(mp[2]) || 
  469.        !Within(mp[3]) || !Within(mp[4]) || !Within(mp[5]))
  470.         return D3DXVECTOR3(0.0f, 1.0f, 0.0f);
  471.  
  472.     //Calculate the normals of the 6 neighboring planes
  473.     D3DXVECTOR3 normal = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  474.  
  475.     for(int i=0;i<6;i++)
  476.     {
  477.         D3DXPLANE plane;
  478.         D3DXPlaneFromPoints(&plane, 
  479.                             &GetWorldPos(INTPOINT(x, y)),
  480.                             &GetWorldPos(mp[i]), 
  481.                             &GetWorldPos(mp[(i + 1) % 6]));
  482.  
  483.         normal +=  D3DXVECTOR3(plane.a, plane.b, plane.c);
  484.     }
  485.  
  486.     D3DXVec3Normalize(&normal, &normal);
  487.     return normal;
  488. }
  489.  
  490. void TERRAIN::AddObject(int type, INTPOINT mappos)
  491. {
  492.     D3DXVECTOR3 pos = D3DXVECTOR3(mappos.x, m_pHeightMap->GetHeight(mappos), -mappos.y);    
  493.     D3DXVECTOR3 rot = D3DXVECTOR3((rand()%1000 / 1000.0f) * 0.13f, (rand()%1000 / 1000.0f) * 3.0f, (rand()%1000 / 1000.0f) * 0.13);
  494.  
  495.     float sca_xz = (rand()%1000 / 1000.0f) * 0.5f + 0.5f;
  496.     float sca_y = (rand()%1000 / 1000.0f) * 1.0f + 0.5f;
  497.     D3DXVECTOR3 sca = D3DXVECTOR3(sca_xz, sca_y, sca_xz);
  498.  
  499.     m_objects.push_back(OBJECT(type, mappos, pos, rot, sca));
  500. }
  501.  
  502. void TERRAIN::Render(CAMERA &camera)
  503. {
  504.     //Set render states        
  505.     m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  506.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);    
  507.     
  508.     m_pDevice->SetTexture(0, m_pAlphaMap);
  509.     m_pDevice->SetTexture(1, m_diffuseMaps[0]);        //Grass
  510.     m_pDevice->SetTexture(2, m_diffuseMaps[1]);        //Mountain
  511.     m_pDevice->SetTexture(3, m_diffuseMaps[2]);        //Snow
  512.     m_pDevice->SetTexture(4, m_pFogOfWarTexture);        //Fog-of-War
  513.  
  514.     m_pDevice->SetMaterial(&m_mtrl);
  515.  
  516.     D3DXMATRIX world, vp = camera.GetViewMatrix() * camera.GetProjectionMatrix();
  517.     D3DXMatrixIdentity(&world);
  518.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  519.     
  520.     //Set vertex shader variables
  521.     m_terrainVS.SetMatrix(m_vsMatW, world);
  522.     m_terrainVS.SetMatrix(m_vsMatVP, vp);
  523.     m_terrainVS.SetVector3(m_vsDirToSun, m_dirToSun);
  524.  
  525.     m_terrainVS.Begin();
  526.     m_terrainPS.Begin();
  527.         
  528.     for(int p=0;p<m_patches.size();p++)
  529.         if(m_patches[p]->m_visible && !camera.Cull(m_patches[p]->m_BBox))
  530.             m_patches[p]->Render();
  531.  
  532.     m_terrainPS.End();
  533.     m_terrainVS.End();
  534.  
  535.     m_pDevice->SetTexture(1, NULL);
  536.     m_pDevice->SetTexture(2, NULL);
  537.     m_pDevice->SetTexture(3, NULL);
  538.     m_pDevice->SetTexture(4, NULL);
  539.  
  540.     //Render Objects
  541.     m_objectsVS.SetMatrix(m_objMatW, world);
  542.     m_objectsVS.SetMatrix(m_objMatVP, vp);
  543.     m_objectsVS.SetVector3(m_objDirToSun, m_dirToSun);
  544.     m_objectsVS.SetVector3(m_objMapSize, D3DXVECTOR3(m_size.x, m_size.y, 0.0f));
  545.  
  546.     m_pDevice->SetTexture(1, m_pFogOfWarTexture);        //Lightmap
  547.     
  548.     m_objectsVS.Begin();
  549.     m_objectsPS.Begin();
  550.  
  551.     for(int i=0;i<m_objects.size();i++)
  552.         if(m_objects[i].m_visible && !camera.Cull(m_objects[i].m_BBox))
  553.         {
  554.             D3DXMATRIX m = m_objects[i].m_meshInstance.GetWorldMatrix();
  555.             m_objectsVS.SetMatrix(m_objMatW, m);
  556.             m_objects[i].Render();
  557.         }
  558.  
  559.     m_objectsVS.End();
  560.     m_objectsPS.End();
  561. }
  562.  
  563. void TERRAIN::Progress(std::string text, float prc)
  564. {
  565.     m_pDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L);
  566.     m_pDevice->BeginScene();
  567.     
  568.     RECT rc = {200, 250, 600, 300};
  569.     m_pProgressFont->DrawText(NULL, text.c_str(), -1, &rc, DT_CENTER | DT_VCENTER | DT_NOCLIP, 0xffffffff);
  570.  
  571.     //Progress bar
  572.     D3DRECT r;
  573.     r.x1 = 200; r.x2 = 600;
  574.     r.y1 = 300; r.y2 = 340;
  575.     m_pDevice->Clear(1, &r, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0L);
  576.     r.x1 = 202; r.x2 = 598;
  577.     r.y1 = 302; r.y2 = 338;
  578.     m_pDevice->Clear(1, &r, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000000, 1.0f, 0L);
  579.     r.x1 = 202; r.x2 = 202 + 396 * prc;
  580.     r.y1 = 302; r.y2 = 338;
  581.     m_pDevice->Clear(1, &r, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff00ff00, 1.0f, 0L);
  582.  
  583.     m_pDevice->EndScene();
  584.     m_pDevice->Present(0, 0, 0, 0);
  585. }
  586.  
  587. void TERRAIN::SetOrthogonalView()
  588. {
  589.     D3DXMATRIX world, view, proj;
  590.  
  591.     //World matrix
  592.     D3DXMatrixIdentity(&world);
  593.  
  594.     //View matrix (eye & focus in the center of the terrain)
  595.     D3DXVECTOR2 center = D3DXVECTOR2((m_size.x - 1) / 2.0f, -(m_size.y - 1) / 2.0f);
  596.  
  597.     D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(center.x, 1000.0f, center.y),
  598.                               &D3DXVECTOR3(center.x, 0.0f, center.y),
  599.                               &D3DXVECTOR3(0.0f, 0.0f, 1.0f));
  600.  
  601.     //Projection matrix
  602.     D3DXMatrixOrthoLH(&proj, m_size.x-1, m_size.y-1, 0.1f, 2000.0f);
  603.  
  604.     //Set transformation matrices
  605.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  606.     m_pDevice->SetTransform(D3DTS_VIEW, &view);
  607.     m_pDevice->SetTransform(D3DTS_PROJECTION, &proj);
  608. }
  609.  
  610. void TERRAIN::UpdateSightMatrices(std::vector<MAPOBJECT*> &mapObjects)
  611. {
  612.     memset(m_pVisibleTiles, false, sizeof(bool) * m_size.x * m_size.y);
  613.     for(int i=0;i<mapObjects.size();i++)
  614.         if(mapObjects[i] != NULL)
  615.         {
  616.             int sr = mapObjects[i]->m_sightRadius, a = 0;
  617.             INTPOINT start = mapObjects[i]->m_mappos - INTPOINT(sr, sr);
  618.             INTPOINT end = mapObjects[i]->m_mappos + INTPOINT(sr, sr);
  619.  
  620.             for(int y=start.y;y<=end.y;y++)
  621.                 for(int x=start.x;x<=end.x;x++)
  622.                     if(x >= 0 && y >= 0 && x < m_size.x && y < m_size.y)
  623.                     {
  624.                         int index = x + y * m_size.x;
  625.                         m_pVisitedTiles[index] = m_pVisibleTiles[index] = true;
  626.                     }
  627.         }
  628.  
  629.     //Calculate visibility variable of Patches
  630.     for(int i=0;i<m_patches.size();i++)
  631.         if(m_patches[i] != NULL)
  632.         {
  633.             m_patches[i]->m_visible = false;
  634.             RECT r = m_patches[i]->m_mapRect;
  635.  
  636.             for(int y=r.top;y<=r.bottom && !m_patches[i]->m_visible;y++)
  637.                 for(int x=r.left;x<=r.right && !m_patches[i]->m_visible;x++)
  638.                     if(m_pVisitedTiles[x + y * m_size.x])
  639.                         m_patches[i]->m_visible = true;
  640.         }
  641.  
  642.     //Calculate visibility of terrain objects
  643.     for(int i=0;i<m_objects.size();i++)
  644.         m_objects[i].m_visible = m_pVisitedTiles[m_objects[i].m_mappos.x + m_objects[i].m_mappos.y * m_size.x];
  645. }
  646.  
  647. void TERRAIN::RenderLandscape()
  648. {
  649.     //Set orthogonal rendering view & projection
  650.     SetOrthogonalView();
  651.  
  652.     //Retrieve the surface of the back buffer
  653.     IDirect3DSurface9 *backSurface = NULL;
  654.     m_pDevice->GetRenderTarget(0, &backSurface);
  655.     
  656.     //Get the surface of the minimap texture
  657.     IDirect3DSurface9 *landScapeSurface = NULL;            
  658.     m_pLandScape->GetSurfaceLevel(0, &landScapeSurface);            
  659.  
  660.     //Set render target to the m_visible surface
  661.     m_pDevice->SetRenderTarget(0, landScapeSurface);
  662.  
  663.     //Clear render target to black
  664.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
  665.  
  666.     m_pDevice->BeginScene();
  667.  
  668.     //Render Terrain
  669.     {
  670.         //Set render states        
  671.         m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  672.         m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  673.  
  674.         //Create completely white lightmap
  675.         IDirect3DTexture9* white = NULL;
  676.         m_pDevice->CreateTexture(32, 32, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &white, NULL);
  677.         D3DLOCKED_RECT sRect;
  678.         white->LockRect(0, &sRect, NULL, NULL);
  679.         memset((BYTE*)sRect.pBits, 255, 32 * 32);
  680.         white->UnlockRect(0);
  681.  
  682.         m_pDevice->SetTexture(0, m_pAlphaMap);
  683.         m_pDevice->SetTexture(1, m_diffuseMaps[0]);        //Grass
  684.         m_pDevice->SetTexture(2, m_diffuseMaps[1]);        //Mountain
  685.         m_pDevice->SetTexture(3, m_diffuseMaps[2]);        //Snow
  686.         m_pDevice->SetTexture(4, white);                //Use White Texture
  687.         m_pDevice->SetMaterial(&m_mtrl);
  688.  
  689.         D3DXMATRIX world, view, proj;
  690.         D3DXMatrixIdentity(&world);
  691.         m_pDevice->SetTransform(D3DTS_WORLD, &world);
  692.         m_pDevice->GetTransform(D3DTS_VIEW, &view);
  693.         m_pDevice->GetTransform(D3DTS_PROJECTION, &proj);
  694.         
  695.         //Set vertex shader variables
  696.         m_terrainVS.SetMatrix(m_vsMatW, world);
  697.         m_terrainVS.SetMatrix(m_vsMatVP, view * proj);
  698.         m_terrainVS.SetVector3(m_vsDirToSun, m_dirToSun);
  699.  
  700.         m_terrainVS.Begin();
  701.         m_terrainPS.Begin();
  702.         for(int p=0;p<m_patches.size();p++)
  703.             m_patches[p]->Render();
  704.         m_terrainPS.End();
  705.         m_terrainVS.End();
  706.  
  707.         for(int i=0;i<8;i++)
  708.             m_pDevice->SetTexture(i, NULL);
  709.  
  710.         //Render Objects
  711.         m_objectsVS.SetMatrix(m_objMatW, world);
  712.         m_objectsVS.SetMatrix(m_objMatVP, view * proj);
  713.         m_objectsVS.SetVector3(m_objDirToSun, m_dirToSun);
  714.         m_objectsVS.SetVector3(m_objMapSize, D3DXVECTOR3(m_size.x, m_size.y, 0.0f));
  715.         m_pDevice->SetTexture(1, white);        //White Texture
  716.         
  717.         m_objectsVS.Begin();
  718.         m_objectsPS.Begin();
  719.  
  720.         for(int i=0;i<m_objects.size();i++)
  721.         {
  722.             D3DXMATRIX m = m_objects[i].m_meshInstance.GetWorldMatrix();
  723.             m_objectsVS.SetMatrix(m_objMatW, m);
  724.             m_objects[i].Render();
  725.         }
  726.  
  727.         m_objectsVS.End();
  728.         m_objectsPS.End();
  729.  
  730.         white->Release();
  731.     }
  732.  
  733.     m_pDevice->EndScene();
  734.  
  735.     //Reset render target to back buffer
  736.     m_pDevice->SetRenderTarget(0, backSurface);
  737.  
  738.     //Release surfaces
  739.     landScapeSurface->Release();
  740.     backSurface->Release();
  741.  
  742.     //D3DXSaveTextureToFile("m_pLandScape.bmp", D3DXIFF_BMP, m_pLandScape, NULL);
  743. }
  744.  
  745. bool TERRAIN::Within(INTPOINT p)
  746. {
  747.     return p.x >= 0 && p.y >= 0 && p.x < m_size.x && p.y < m_size.y;
  748. }
  749.  
  750. void TERRAIN::InitPathfinding()
  751. {
  752.     try
  753.     {
  754.         //Read maptile heights & types from heightmap
  755.         for(int y=0;y<m_size.y;y++)
  756.             for(int x=0;x<m_size.x;x++)
  757.             {
  758.                 MAPTILE *tile = GetTile(x, y);
  759.                 if(m_pHeightMap != NULL)tile->m_height = m_pHeightMap->GetHeight(x, y);
  760.                 tile->m_mappos = INTPOINT(x, y);
  761.                 
  762.                 if(tile->m_height < 0.3f)         tile->m_type = 0;    //Grass
  763.                 else if(tile->m_height < 7.0f) tile->m_type = 1;    //Stone
  764.                 else                         tile->m_type = 2;    //Snow
  765.             }
  766.  
  767.         //Calculate tile cost as a function of the height variance
  768.         for(int y=0;y<m_size.y;y++)        
  769.             for(int x=0;x<m_size.x;x++)
  770.             {
  771.                 MAPTILE *tile = GetTile(x, y);
  772.  
  773.                 if(tile != NULL)
  774.                 {
  775.                     //Possible neighbors
  776.                     INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
  777.                                     INTPOINT(x-1, y),                      INTPOINT(x+1, y),
  778.                                     INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};
  779.  
  780.                     float variance = 0.0f;
  781.                     int nr = 0;
  782.  
  783.                     //For each neighbor
  784.                     for(int i=0;i<8;i++)    
  785.                         if(Within(p[i]))
  786.                         {
  787.                             MAPTILE *neighbor = GetTile(p[i]);
  788.  
  789.                             if(neighbor != NULL)
  790.                             {
  791.                                 float v = neighbor->m_height - tile->m_height;
  792.                                 variance += (v * v);
  793.                                 nr++;
  794.                             }
  795.                         }
  796.  
  797.                     //Cost = height variance
  798.                     variance /= (float)nr;
  799.                     tile->m_cost = variance + 0.1f;
  800.                     if(tile->m_cost > 1.0f)tile->m_cost = 1.0f;
  801.  
  802.                     //If the tile cost is less than 1.0f, then we can walk on the tile
  803.                     tile->m_walkable = tile->m_cost < 0.5f;
  804.                 }
  805.             }
  806.  
  807.         //Make maptiles with objects on them not walkable
  808.         for(int i=0;i<m_objects.size();i++)
  809.         {
  810.             MAPTILE *tile = GetTile(m_objects[i].m_mappos);
  811.             if(tile != NULL)
  812.             {
  813.                 tile->m_walkable = false;
  814.                 tile->m_cost = 1.0f;
  815.             }
  816.         }
  817.  
  818.         //Connect m_pMapTiles using the neightbors[] pointers
  819.         for(int y=0;y<m_size.y;y++)        
  820.             for(int x=0;x<m_size.x;x++)
  821.             {
  822.                 MAPTILE *tile = GetTile(x, y);
  823.                 if(tile != NULL && tile->m_walkable)
  824.                 {
  825.                     //Clear old connections
  826.                     for(int i=0;i<8;i++)
  827.                         tile->neighbors[i] = NULL;
  828.  
  829.                     //Possible neighbors
  830.                     INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
  831.                                     INTPOINT(x-1, y),                      INTPOINT(x+1, y),
  832.                                     INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};
  833.  
  834.                     //For each neighbor
  835.                     for(int i=0;i<8;i++)    
  836.                         if(Within(p[i]))
  837.                         {
  838.                             MAPTILE *neighbor = GetTile(p[i]);
  839.  
  840.                             //Connect tiles if the neighbor is walkable
  841.                             if(neighbor != NULL && neighbor->m_walkable)
  842.                                 tile->neighbors[i] = neighbor;
  843.                         }
  844.                 }
  845.             }
  846.  
  847.         CreateTileSets();
  848.     }
  849.     catch(...)
  850.     {
  851.         debug.Print("Error in InitPathfinding()");
  852.     }    
  853. }
  854.  
  855. void TERRAIN::UpdatePathfinding(RECT *r)
  856. {
  857.     if(r == NULL)
  858.     {
  859.         InitPathfinding();
  860.         return;
  861.     }
  862.  
  863.     //Connect maptiles using the neightbors[] pointers
  864.     for(int y=r->top; y<=r->bottom; y++)        
  865.         for(int x=r->left; x<=r->right; x++)
  866.         {
  867.             MAPTILE *tile = GetTile(x, y);
  868.             if(tile != NULL && tile->m_walkable)
  869.             {
  870.                 //Clear old connections
  871.                 for(int i=0;i<8;i++)
  872.                     tile->neighbors[i] = NULL;
  873.  
  874.                 //Possible neighbors
  875.                 INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
  876.                                 INTPOINT(x-1, y),                      INTPOINT(x+1, y),
  877.                                 INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};
  878.  
  879.                 //For each neighbor
  880.                 for(int i=0;i<8;i++)
  881.                     if(Within(p[i]))
  882.                     {
  883.                         MAPTILE *neighbor = GetTile(p[i]);
  884.  
  885.                         //Connect tiles if the neighbor is m_walkable
  886.                         if(neighbor != NULL && neighbor->m_walkable)
  887.                             tile->neighbors[i] = neighbor;
  888.                     }
  889.             }
  890.         }
  891.  
  892.     CreateTileSets();
  893. }
  894.  
  895. void TERRAIN::CreateTileSets()
  896. {
  897.     try
  898.     {
  899.         int setNo = 0;
  900.         for(int y=0;y<m_size.y;y++)        //Set a unique set for each tile...
  901.             for(int x=0;x<m_size.x;x++)
  902.                 m_pMapTiles[x + y * m_size.x].m_set = setNo++;
  903.  
  904.         bool changed = true;
  905.  
  906.         while(changed)
  907.         {
  908.             changed = false;
  909.  
  910.             for(int y=0;y<m_size.y;y++)
  911.                 for(int x=0;x<m_size.x;x++)
  912.                 {
  913.                     MAPTILE *tile = GetTile(x, y);
  914.  
  915.                     //Find the lowest set of a neighbor
  916.                     if(tile != NULL && tile->m_walkable)
  917.                     {
  918.                         for(int i=0;i<8;i++)
  919.                             if(tile->neighbors[i] != NULL &&
  920.                                 tile->neighbors[i]->m_walkable &&
  921.                                 tile->neighbors[i]->m_set < tile->m_set)
  922.                             {
  923.                                 changed = true;
  924.                                 tile->m_set = tile->neighbors[i]->m_set;
  925.                             }
  926.                     }
  927.                 }
  928.         }
  929.     }
  930.     catch(...)
  931.     {
  932.         debug.Print("Error in TERRAIN::CreateTileSets()");
  933.     }
  934. }
  935.  
  936. float H(INTPOINT a, INTPOINT b)
  937. {
  938.     return abs(a.x - b.x) + abs(a.y - b.y);
  939.     //return a.Distance(b);
  940. }
  941.  
  942. std::vector<INTPOINT> TERRAIN::GetPath(INTPOINT start, INTPOINT goal, bool considerUnits, MAPOBJECT *unit)
  943. {
  944.     try
  945.     {
  946.         //Check that the two points are within the bounds of the map
  947.         MAPTILE *startTile = GetTile(start);
  948.         MAPTILE *goalTile = GetTile(goal);
  949.         
  950.         if(!Within(start) || !Within(goal) || start == goal || startTile == NULL || goalTile == NULL)
  951.             return std::vector<INTPOINT>();
  952.  
  953.         //Check if a path exists
  954.         if(!startTile->m_walkable || !goalTile->m_walkable || startTile->m_set != goalTile->m_set)
  955.             return std::vector<INTPOINT>();
  956.  
  957.         //Check that goal tile isnt busy if considering units
  958.         if(considerUnits && goalTile->m_pMapObject != NULL)
  959.             goal = GetClosestFreeTile(goal, start);
  960.  
  961.         if(H(start, goal) < 10 && considerUnits && !PositionAccessible(unit, goal))
  962.             return std::vector<INTPOINT>();
  963.  
  964.         //Init Search
  965.         long numTiles = m_size.x * m_size.y;
  966.         for(long l=0;l<numTiles;l++)
  967.         {
  968.             m_pMapTiles[l].f = m_pMapTiles[l].g = INT_MAX;        //Clear F,G
  969.             m_pMapTiles[l].open = m_pMapTiles[l].closed = false;    //Reset Open and Closed
  970.         }
  971.  
  972.         std::vector<MAPTILE*> open;                //Create Our Open list
  973.         startTile->g = 0;                        //Init our starting point (SP)
  974.         startTile->f = H(start, goal);
  975.         startTile->open = true;
  976.         open.push_back(startTile);                //Add SP to the Open list
  977.  
  978.         bool found = false;                    // Search as long as a path hasnt been found,
  979.  
  980.         while(!found && !open.empty())        // or there is no more tiles to search
  981.         {    
  982.             MAPTILE * best = open[0];        // Find the best tile (i.e. the lowest F value)
  983.             int bestPlace = 0;
  984.             for(int i=1;i<open.size();i++)
  985.                 if(open[i] != NULL && open[i]->f < best->f)
  986.                 {
  987.                     best = open[i];
  988.                     bestPlace = i;
  989.                 }
  990.             
  991.             if(best == NULL)break;            //No path found
  992.             if(considerUnits && open.size() > 100)break;
  993.  
  994.             open[bestPlace]->open = false;
  995.             open.erase(&open[bestPlace]);    // Take the best node out of the Open list
  996.  
  997.             if(best->m_mappos == goal)        //If the goal has been found
  998.             {
  999.                 std::vector<INTPOINT> p, p2;
  1000.                 MAPTILE *point = best;
  1001.  
  1002.                 while(point->m_mappos != start && point != NULL)    // Generate path
  1003.                 {
  1004.                     p.push_back(point->m_mappos);
  1005.                     point = point->m_pParent;
  1006.  
  1007.                     if(p.size() > 500)        //Too long path, something is wrong
  1008.                         return std::vector<INTPOINT>();
  1009.                 }
  1010.  
  1011.                 for(int i=p.size()-1;i!=0;i--)    // Reverse path
  1012.                     p2.push_back(p[i]);
  1013.                 p2.push_back(goal);
  1014.  
  1015.                 return p2;
  1016.             }
  1017.             else
  1018.             {
  1019.                 for(i=0;i<8;i++)                    // otherwise, check the neighbors of the
  1020.                     if(best->neighbors[i] != NULL)    // best tile
  1021.                         if(!considerUnits || best->neighbors[i]->m_pMapObject == NULL)
  1022.                         {
  1023.                             bool inList = false;        // Generate new G and F value
  1024.                             float newG = best->g + 1.0f;
  1025.                             float d = H(best->m_mappos, best->neighbors[i]->m_mappos);
  1026.                             float newF = newG + H(best->neighbors[i]->m_mappos, goal) + best->neighbors[i]->m_cost * 5.0f * d;
  1027.  
  1028.                             if(best->neighbors[i]->open || best->neighbors[i]->closed)
  1029.                             {
  1030.                                 if(newF < best->neighbors[i]->f)    // If the new F value is lower
  1031.                                 {
  1032.                                     best->neighbors[i]->g = newG;    // update the values of this tile
  1033.                                     best->neighbors[i]->f = newF;
  1034.                                     best->neighbors[i]->m_pParent = best;                                
  1035.                                 }
  1036.                                 inList = true;
  1037.                             }
  1038.  
  1039.                             if(!inList)            // If the neighbor tile isn't in the Open or Closed list
  1040.                             {
  1041.                                 best->neighbors[i]->f = newF;        //Set the values
  1042.                                 best->neighbors[i]->g = newG;
  1043.                                 best->neighbors[i]->m_pParent = best;
  1044.                                 best->neighbors[i]->open = true;
  1045.                                 open.push_back(best->neighbors[i]);    //Add it to the open list    
  1046.                             }
  1047.                         }
  1048.  
  1049.                 best->closed = true;        //The best tile has now been searched, add it to the Closed list
  1050.             }
  1051.         }
  1052.  
  1053.         return std::vector<INTPOINT>();        //No path found, return an empty path        
  1054.     }
  1055.     catch(...)
  1056.     {
  1057.         debug.Print("Error in TERRAIN::GetPath()");
  1058.         return std::vector<INTPOINT>();
  1059.     }
  1060. }
  1061.  
  1062. MAPTILE* TERRAIN::GetTile(int x, int y)
  1063. {
  1064.     if(m_pMapTiles == NULL)return NULL;
  1065.  
  1066.     try
  1067.     {
  1068.         if(Within(INTPOINT(x, y)))
  1069.             return &m_pMapTiles[x + y * m_size.x];
  1070.         else return NULL;
  1071.     }
  1072.     catch(...)
  1073.     {
  1074.         return NULL;
  1075.     }
  1076. }
  1077.  
  1078. void TERRAIN::SaveTerrain(char fileName[])
  1079. {
  1080.     try
  1081.     {
  1082.         std::ofstream out(fileName, std::ios::binary);        //Binary format
  1083.  
  1084.         if(out.good())
  1085.         {
  1086.             out.write((char*)&m_size, sizeof(INTPOINT));    //Write map size
  1087.  
  1088.             //Write all the maptile information needed to recreate the map
  1089.             for(int y=0;y<m_size.y;y++)
  1090.                 for(int x=0;x<m_size.x;x++)
  1091.                 {
  1092.                     MAPTILE *tile = GetTile(x, y);
  1093.                     out.write((char*)&tile->m_type, sizeof(int));            //type
  1094.                     out.write((char*)&tile->m_height, sizeof(float));        //Height
  1095.                 }
  1096.  
  1097.             //Write all the objects
  1098.             int numObjects = m_objects.size();
  1099.             out.write((char*)&numObjects, sizeof(int));     //Num Objects
  1100.             for(int i=0;i<m_objects.size();i++)
  1101.             {
  1102.                 out.write((char*)&m_objects[i].m_type, sizeof(int));                //type
  1103.                 out.write((char*)&m_objects[i].m_mappos, sizeof(INTPOINT));            //mappos
  1104.                 out.write((char*)&m_objects[i].m_meshInstance.m_pos, sizeof(D3DXVECTOR3));    //Pos
  1105.                 out.write((char*)&m_objects[i].m_meshInstance.m_rot, sizeof(D3DXVECTOR3));    //Rot
  1106.                 out.write((char*)&m_objects[i].m_meshInstance.m_sca, sizeof(D3DXVECTOR3));    //Sca
  1107.             }
  1108.         }
  1109.  
  1110.         out.close();
  1111.     }
  1112.     catch(...)
  1113.     {
  1114.         debug.Print("Error in TERRAIN::SaveTerrain()");
  1115.     }
  1116. }
  1117.  
  1118. void TERRAIN::LoadTerrain(char fileName[])
  1119. {
  1120.     try
  1121.     {
  1122.         std::ifstream in(fileName, std::ios::binary);        //Binary format
  1123.  
  1124.         if(in.good())
  1125.         {
  1126.             Release();    //Release all terrain resources
  1127.  
  1128.             in.read((char*)&m_size, sizeof(INTPOINT));    //read map size
  1129.         
  1130.             if(m_pMapTiles != NULL)    //Clear old m_pMapTiles
  1131.                 delete [] m_pMapTiles;
  1132.  
  1133.             //Create new maptiles
  1134.             m_pMapTiles = new MAPTILE[m_size.x * m_size.y];
  1135.             memset(m_pMapTiles, 0, sizeof(MAPTILE)*m_size.x*m_size.y);
  1136.  
  1137.  
  1138.             //Read the maptile information
  1139.             for(int y=0;y<m_size.y;y++)
  1140.                 for(int x=0;x<m_size.x;x++)
  1141.                 {
  1142.                     MAPTILE *tile = GetTile(x, y);
  1143.                     in.read((char*)&tile->m_type, sizeof(int));            //type
  1144.                     in.read((char*)&tile->m_height, sizeof(float));        //Height
  1145.                 }
  1146.  
  1147.             //Read number of objects
  1148.             int numObjects = 0;
  1149.             in.read((char*)&numObjects, sizeof(int));
  1150.             for(int i=0;i<numObjects;i++)
  1151.             {
  1152.                 int type = 0;
  1153.                 INTPOINT mp;
  1154.                 D3DXVECTOR3 p, r, s;
  1155.  
  1156.                 in.read((char*)&type, sizeof(int));            //type
  1157.                 in.read((char*)&mp, sizeof(INTPOINT));        //mappos
  1158.                 in.read((char*)&p, sizeof(D3DXVECTOR3));    //Pos
  1159.                 in.read((char*)&r, sizeof(D3DXVECTOR3));    //Rot
  1160.                 in.read((char*)&s, sizeof(D3DXVECTOR3));    //Sca
  1161.  
  1162.                 m_objects.push_back(OBJECT(type, mp, p, r, s));
  1163.             }
  1164.  
  1165.             //Recreate Terrain
  1166.             InitPathfinding();
  1167.             CreatePatches(3);
  1168.             CalculateAlphaMaps();
  1169.             CalculateLightMap(true);
  1170.         }
  1171.  
  1172.         in.close();
  1173.     }
  1174.     catch(...)
  1175.     {
  1176.         debug.Print("Error in TERRAIN::LoadTerrain()");
  1177.     }
  1178. }
  1179.  
  1180. D3DXVECTOR3 TERRAIN::GetWorldPos(INTPOINT mappos)
  1181. {
  1182.     if(!Within(mappos))return D3DXVECTOR3(0, 0, 0);
  1183.     MAPTILE *tile = GetTile(mappos);
  1184.     return D3DXVECTOR3(mappos.x, tile->m_height, -mappos.y);
  1185. }
  1186.  
  1187. INTPOINT TERRAIN::GetClosestFreeTile(INTPOINT to, INTPOINT from)
  1188. {
  1189.     MAPTILE *tile = GetTile(to);
  1190.     if(tile != NULL && tile->m_walkable && tile->m_pMapObject == NULL)
  1191.         return to;
  1192.  
  1193.     try
  1194.     {
  1195.         for(int i=0;i<3;i++)    //Search radius
  1196.         {
  1197.             std::vector<MAPTILE*> tiles;
  1198.  
  1199.             //Get tiles in current search radius
  1200.             for(int y=to.y - i;y<=to.y + i;y++)
  1201.             {
  1202.                 tiles.push_back(GetTile(to.x - i, y));
  1203.                 tiles.push_back(GetTile(to.x + i, y));
  1204.             }
  1205.  
  1206.             for(int x=to.x - i + 1;x<=to.x + i - 1;x++)
  1207.             {
  1208.                 tiles.push_back(GetTile(x, to.y - i));
  1209.                 tiles.push_back(GetTile(x, to.y + i));
  1210.             }
  1211.  
  1212.             //Find closest tile...
  1213.             MAPTILE *closest = NULL;
  1214.             float dist = 10000.0f;
  1215.  
  1216.             for(int t=0;t<tiles.size();t++)
  1217.                 if(tiles[t] != NULL)
  1218.                     if(tiles[t]->m_walkable && tiles[t]->m_pMapObject == NULL)
  1219.                     {
  1220.                         float d = from.Distance(tiles[t]->m_mappos);
  1221.                         if(d < dist)
  1222.                         {
  1223.                             dist = d;
  1224.                             closest = tiles[t];
  1225.                         }
  1226.                     }
  1227.  
  1228.             if(closest != NULL)
  1229.                 return closest->m_mappos;
  1230.         }
  1231.     }
  1232.     catch(...)
  1233.     {
  1234.         debug.Print("Error in TERRAIN::GetClosestFreeTile()");
  1235.     }
  1236.  
  1237.     return to;
  1238. }
  1239.  
  1240. bool TERRAIN::PositionAccessible(MAPOBJECT *unit, INTPOINT position)
  1241. {
  1242.     if(unit == NULL || !Within(unit->m_mappos) || !Within(position))return false;
  1243.  
  1244.     //Set start and end location of the search
  1245.     INTPOINT start = unit->m_mappos;
  1246.     INTPOINT end = position;
  1247.     if(start.x > end.x)std::swap(start.x, end.x);
  1248.     if(start.y > end.y)std::swap(start.y, end.y);
  1249.  
  1250.     if(H(start, end) >= 9)
  1251.         return true;
  1252.  
  1253.     //Set the open variable of search area's mapTiles to false
  1254.     int searchBorder = 3;
  1255.     for(int y=start.y - searchBorder;y<=end.y + searchBorder;y++)
  1256.         for(int x=start.x - searchBorder;x<=end.x + searchBorder;x++)
  1257.             if(Within(INTPOINT(x, y)))
  1258.                 m_pMapTiles[y * m_size.x + x].open = false;
  1259.  
  1260.     //Set the open variable of the start location to true
  1261.     m_pMapTiles[position.y * m_size.x + position.x].open = true;
  1262.     searchBorder--;
  1263.  
  1264.     //Iterate any open nodes to its neighbors if they are unoccupied by units
  1265.     bool changed;
  1266.  
  1267.     do
  1268.     {
  1269.         changed = false;
  1270.  
  1271.         for(int y=start.y - searchBorder;y<=end.y + searchBorder;y++)
  1272.             for(int x=start.x - searchBorder;x<=end.x + searchBorder;x++)
  1273.                 if(Within(INTPOINT(x, y)) && !m_pMapTiles[y * m_size.x + x].open)
  1274.                     for(int i=0;i<8;i++)
  1275.                     {
  1276.                         MAPTILE *t = m_pMapTiles[y * m_size.x + x].neighbors[i];
  1277.                         if(t != NULL && t->open && (t->m_pMapObject == NULL || t->m_pMapObject == unit))
  1278.                         {
  1279.                             m_pMapTiles[y * m_size.x + x].open = true;
  1280.                             changed = true;
  1281.                             i = 8;
  1282.                         }
  1283.                     }
  1284.  
  1285.         //If the open variable of the end node is true then a path exists
  1286.         if(m_pMapTiles[unit->m_mappos.y * m_size.x + unit->m_mappos.x].open)
  1287.             return true;
  1288.     }
  1289.     while(changed);
  1290.     
  1291.     //No path exists
  1292.     return false;
  1293. }